4 // Copyright (c) 2006 Microsoft Corporation. All rights reserved.
6 // The use and distribution terms for this software are contained in the file
7 // named license.txt, which can be found in the root of this distribution.
8 // By using this software in any fashion, you are agreeing to be bound by the
9 // terms of this license.
11 // You must not remove this notice, or any other, from this software.
16 namespace Microsoft
.JScript
{
18 using Microsoft
.JScript
.Vsa
;
20 using System
.Collections
;
21 using System
.Globalization
;
23 using System
.Text
.RegularExpressions
;
25 public class StringPrototype
: StringObject
{
26 internal static readonly StringPrototype ob
= new StringPrototype(FunctionPrototype
.ob
, ObjectPrototype
.ob
);
27 internal static StringConstructor _constructor
;
29 internal StringPrototype(FunctionPrototype funcprot
, ObjectPrototype parent
)
31 this.noExpando
= true;
34 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_anchor
)]
35 public static String
anchor(Object thisob
, Object anchorName
){
36 String thisStr
= Convert
.ToString(thisob
);
37 String anchorStr
= Convert
.ToString(anchorName
);
38 return "<A NAME=\""+anchorStr
+"\">"+thisStr
+"</A>";
41 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_big
)]
42 public static String
big(Object thisob
){
43 return "<BIG>"+Convert
.ToString(thisob
)+"</BIG>";
46 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_blink
)]
47 public static String
blink(Object thisob
){
48 return "<BLINK>"+Convert
.ToString(thisob
)+"</BLINK>";
51 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_bold
)]
52 public static String
bold(Object thisob
){
53 return "<B>"+Convert
.ToString(thisob
)+"</B>";
56 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_charAt
)]
57 public static String
charAt(Object thisob
, double pos
){
58 String thisStr
= Convert
.ToString(thisob
);
59 double position
= Convert
.ToInteger(pos
);
60 if (position
< 0 || !(position
< thisStr
.Length
))
62 return thisStr
.Substring((int)position
, 1);
65 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_charCodeAt
)]
66 public static Object
charCodeAt(Object thisob
, double pos
){ //This returns an object so that integers stay integers
67 String thisStr
= Convert
.ToString(thisob
);
68 double position
= Convert
.ToInteger(pos
);
69 if (position
< 0 || !(position
< thisStr
.Length
))
71 return (int)(thisStr
[(int)position
]);
74 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
|JSFunctionAttributeEnum
.HasVarArgs
, JSBuiltin
.String_concat
)]
75 public static String
concat(Object thisob
, params Object
[] args
){
76 StringBuilder concat
= new StringBuilder(Convert
.ToString(thisob
));
77 for (int i
= 0; i
< args
.Length
; i
++)
78 concat
.Append(Convert
.ToString(args
[i
]));
79 return concat
.ToString();
82 public static StringConstructor constructor
{
84 return StringPrototype
._constructor
;
88 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_fixed
)]
89 public static String
@fixed(Object thisob
){
90 return "<TT>"+Convert
.ToString(thisob
)+"</TT>";
93 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_fontcolor
)]
94 public static String
fontcolor(Object thisob
, Object colorName
){
95 String thisStr
= Convert
.ToString(thisob
);
96 String colorStr
= Convert
.ToString(thisob
);
97 return "<FONT COLOR=\""+colorStr
+"\">"+thisStr
+"</FONT>";
100 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_fontsize
)]
101 public static String
fontsize(Object thisob
, Object fontSize
){
102 String thisStr
= Convert
.ToString(thisob
);
103 String fontStr
= Convert
.ToString(fontSize
);
104 return "<FONT SIZE=\""+fontStr
+"\">"+thisStr
+"</FONT>";
107 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_indexOf
)]
108 public static int indexOf(Object thisob
, Object searchString
, double position
){
109 String thisStr
= Convert
.ToString(thisob
);
110 String searchStr
= Convert
.ToString(searchString
);
111 double startIndex
= Convert
.ToInteger(position
);
112 int length
= thisStr
.Length
;
115 if (startIndex
>= length
)
116 return searchStr
.Length
== 0 ? 0 : -1;
117 return thisStr
.IndexOf(searchStr
, (int)startIndex
);
120 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_italics
)]
121 public static String
italics(Object thisob
){
122 return "<I>"+Convert
.ToString(thisob
)+"</I>";
125 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_lastIndexOf
)]
126 public static int lastIndexOf(Object thisob
, Object searchString
, double position
){
127 String thisStr
= Convert
.ToString(thisob
);
128 String searchStr
= Convert
.ToString(searchString
);
129 int length
= thisStr
.Length
;
130 int j
= position
!= position
|| position
> length
? length
: (int)position
;
135 int slength
= searchStr
.Length
;
138 int k
= j
- 1 + slength
;
143 return thisStr
.LastIndexOf(searchStr
, k
);
146 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_link
)]
147 public static String
link(Object thisob
, Object linkRef
){
148 String thisStr
= Convert
.ToString(thisob
);
149 String linkStr
= Convert
.ToString(linkRef
);
150 return "<A HREF=\""+linkStr
+"\">"+thisStr
+"</A>";
153 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_localeCompare
)]
154 public static int localeCompare(Object thisob
, Object thatob
){
155 return String
.Compare(Convert
.ToString(thisob
), Convert
.ToString(thatob
), StringComparison
.CurrentCulture
);
158 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
|JSFunctionAttributeEnum
.HasEngine
, JSBuiltin
.String_match
)]
159 public static Object
match(Object thisob
, VsaEngine engine
, Object regExp
){
160 String thisStr
= Convert
.ToString(thisob
);
161 RegExpObject regExpObject
= StringPrototype
.ToRegExpObject(regExp
, engine
);
163 if (!regExpObject
.globalInt
){
164 match
= regExpObject
.regex
.Match(thisStr
);
166 regExpObject
.lastIndexInt
= 0;
169 if (regExpObject
.regExpConst
!= null){
170 regExpObject
.lastIndexInt
= regExpObject
.regExpConst
.UpdateConstructor(regExpObject
.regex
, match
, thisStr
);
171 return new RegExpMatch(regExpObject
.regExpConst
.arrayPrototype
, regExpObject
.regex
, match
, thisStr
);
173 return new RegExpMatch(engine
.Globals
.globalObject
.originalRegExp
.arrayPrototype
, regExpObject
.regex
, match
, thisStr
);
175 MatchCollection matches
= regExpObject
.regex
.Matches(thisStr
);
176 if (matches
.Count
== 0){
177 regExpObject
.lastIndexInt
= 0;
180 match
= matches
[matches
.Count
- 1];
181 regExpObject
.lastIndexInt
= regExpObject
.regExpConst
.UpdateConstructor(regExpObject
.regex
, match
, thisStr
);
182 return new RegExpMatch(
183 regExpObject
.regExpConst
.arrayPrototype
, regExpObject
.regex
, matches
, thisStr
);
186 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_replace
)]
187 public static String
replace(Object thisob
, Object regExp
, Object replacement
){
188 String thisStr
= Convert
.ToString(thisob
);
189 RegExpObject regExpObject
= regExp
as RegExpObject
;
190 if (regExpObject
!= null) return StringPrototype
.ReplaceWithRegExp(thisStr
, regExpObject
, replacement
);
191 Regex regex
= regExp
as Regex
;
192 if (regex
!= null) return StringPrototype
.ReplaceWithRegExp(thisStr
, new RegExpObject(regex
), replacement
);
193 return StringPrototype
.ReplaceWithString(thisStr
, Convert
.ToString(regExp
), Convert
.ToString(replacement
));
196 private static String
ReplaceWithRegExp(String thisob
, RegExpObject regExpObject
, Object replacement
){
197 RegExpReplace replacer
= replacement
is ScriptFunction
198 ? (RegExpReplace
)(new ReplaceUsingFunction(regExpObject
.regex
, (ScriptFunction
)replacement
, thisob
))
199 : (RegExpReplace
)(new ReplaceWithString(Convert
.ToString(replacement
)));
200 MatchEvaluator matchEvaluator
= new MatchEvaluator(replacer
.Evaluate
);
201 String newString
= regExpObject
.globalInt
202 ? regExpObject
.regex
.Replace(thisob
, matchEvaluator
)
203 : regExpObject
.regex
.Replace(thisob
, matchEvaluator
, 1);
204 regExpObject
.lastIndexInt
= replacer
.lastMatch
== null
206 : regExpObject
.regExpConst
.UpdateConstructor(regExpObject
.regex
, replacer
.lastMatch
, thisob
);
210 private static String
ReplaceWithString(String thisob
, String searchString
, String replaceString
){
211 int index
= thisob
.IndexOf(searchString
);
214 StringBuilder newString
= new StringBuilder(thisob
.Substring(0, index
));
215 newString
.Append(replaceString
);
216 newString
.Append(thisob
.Substring(index
+ searchString
.Length
));
217 return newString
.ToString();
220 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
|JSFunctionAttributeEnum
.HasEngine
, JSBuiltin
.String_search
)]
221 public static int search(Object thisob
, VsaEngine engine
, Object regExp
){
222 String thisStr
= Convert
.ToString(thisob
);
223 RegExpObject regExpObject
= StringPrototype
.ToRegExpObject(regExp
, engine
);
224 Match match
= regExpObject
.regex
.Match(thisStr
);
226 regExpObject
.lastIndexInt
= 0;
229 regExpObject
.lastIndexInt
= regExpObject
.regExpConst
.UpdateConstructor(regExpObject
.regex
, match
, thisStr
);
233 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_slice
)]
234 public static String
slice(Object thisob
, double start
, Object end
){
235 String thisStr
= Convert
.ToString(thisob
);
236 int length
= thisStr
.Length
;
237 double startIndex
= Convert
.ToInteger(start
);
238 double endIndex
= (end
== null || end
is Missing
)
239 ? length
: Convert
.ToInteger(end
);
241 startIndex
= length
+ startIndex
;
245 if (startIndex
> length
)
248 endIndex
= length
+ endIndex
;
252 if (endIndex
> length
)
254 int nChars
= (int)(endIndex
- startIndex
);
258 return thisStr
.Substring((int)startIndex
, nChars
);
261 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_small
)]
262 public static String
small(Object thisob
){
263 return "<SMALL>"+Convert
.ToString(thisob
)+"</SMALL>";
266 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
|JSFunctionAttributeEnum
.HasEngine
, JSBuiltin
.String_split
)]
267 public static ArrayObject
split(Object thisob
, VsaEngine engine
, Object separator
, Object limit
){
268 String thisStr
= Convert
.ToString(thisob
);
269 uint limitValue
= UInt32
.MaxValue
;
270 if (limit
!= null && !(limit
is Missing
) && limit
!= DBNull
.Value
){
271 double lmt
= Convert
.ToInteger(limit
);
272 if (lmt
>= 0 && lmt
< UInt32
.MaxValue
)
273 limitValue
= (uint)lmt
;
276 return (ArrayObject
)engine
.GetOriginalArrayConstructor().Construct();
277 if (separator
== null || separator
is Missing
){
278 ArrayObject array
= (ArrayObject
)engine
.GetOriginalArrayConstructor().Construct();
279 array
.SetValueAtIndex(0, thisob
);
282 RegExpObject regExpObject
= separator
as RegExpObject
;
283 if (regExpObject
!= null) return StringPrototype
.SplitWithRegExp(thisStr
, engine
, regExpObject
, limitValue
);
284 Regex regex
= separator
as Regex
;
285 if (regex
!= null) return StringPrototype
.SplitWithRegExp(thisStr
, engine
, new RegExpObject(regex
), limitValue
);
286 return StringPrototype
.SplitWithString(thisStr
, engine
, Convert
.ToString(separator
), limitValue
);
289 private static ArrayObject
SplitWithRegExp(String thisob
, VsaEngine engine
, RegExpObject regExpObject
, uint limit
){
290 ArrayObject array
= (ArrayObject
)engine
.GetOriginalArrayConstructor().Construct();
291 Match match
= regExpObject
.regex
.Match(thisob
);
294 array
.SetValueAtIndex(0, thisob
);
295 regExpObject
.lastIndexInt
= 0;
305 int len
= match
.Index
- prevIndex
;
308 array
.SetValueAtIndex(i
++, thisob
.Substring(prevIndex
, len
));
309 if (limit
> 0 && i
>= limit
){
310 regExpObject
.lastIndexInt
= regExpObject
.regExpConst
.UpdateConstructor(regExpObject
.regex
, match
, thisob
);
316 prevIndex
= match
.Index
+ match
.Length
;
318 match
= match
.NextMatch();
319 }while(match
.Success
);
321 if (prevIndex
< thisob
.Length
)
322 array
.SetValueAtIndex(i
, thisob
.Substring(prevIndex
));
323 regExpObject
.lastIndexInt
= regExpObject
.regExpConst
.UpdateConstructor(regExpObject
.regex
, lastMatch
, thisob
);
328 private static ArrayObject
SplitWithString(String thisob
, VsaEngine engine
, String separator
, uint limit
){
329 ArrayObject array
= (ArrayObject
)engine
.GetOriginalArrayConstructor().Construct();
330 if (separator
.Length
== 0){
331 if (limit
> thisob
.Length
)
332 limit
= (uint)thisob
.Length
;
333 for (int i
= 0; i
< limit
; i
++)
334 array
.SetValueAtIndex((uint)i
, thisob
[i
].ToString());
339 while ((index
= thisob
.IndexOf(separator
, prevIndex
)) >= 0){
340 array
.SetValueAtIndex(i
++, thisob
.Substring(prevIndex
, index
-prevIndex
));
343 prevIndex
= index
+ separator
.Length
;
346 array
.SetValueAtIndex(0, thisob
);
348 array
.SetValueAtIndex(i
, thisob
.Substring(prevIndex
));
353 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_strike
)]
354 public static String
strike(Object thisob
){
355 return "<STRIKE>"+Convert
.ToString(thisob
)+"</STRIKE>";
358 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_sub
)]
359 public static String
sub(Object thisob
){
360 return "<SUB>"+Convert
.ToString(thisob
)+"</SUB>";
363 [NotRecommended("substr")]
364 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_substr
)]
365 public static String
substr(Object thisob
, double start
, Object count
){
366 String thisStr
= thisob
as String
;
367 if (thisStr
== null) thisStr
= Convert
.ToString(thisob
);
368 int length
= thisStr
.Length
;
369 double startIndex
= Convert
.ToInteger(start
);
371 startIndex
+= length
;
374 else if (startIndex
> length
)
376 int nChars
= count
is int ? (int)count
:
377 ((count
== null || count
is Missing
) ? length
-(int)Runtime
.DoubleToInt64(startIndex
) : (int)Runtime
.DoubleToInt64(Convert
.ToInteger(count
)));
378 if (startIndex
+nChars
> length
)
379 nChars
= length
- (int)startIndex
;
383 return thisStr
.Substring((int)startIndex
, nChars
);
386 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_substring
)]
387 public static String
substring(Object thisob
, double start
, Object end
){
388 String thisStr
= thisob
as String
;
389 if (thisStr
== null) thisStr
= Convert
.ToString(thisob
);
390 int length
= thisStr
.Length
;
391 double startIndex
= Convert
.ToInteger(start
);
394 else if (startIndex
> length
)
396 double endIndex
= (end
== null || end
is Missing
)
397 ? length
: Convert
.ToInteger(end
);
400 else if (endIndex
> length
)
402 if (startIndex
> endIndex
){
403 double temp
= startIndex
;
404 startIndex
= endIndex
;
407 return thisStr
.Substring((int)startIndex
, (int)(endIndex
- startIndex
));
410 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_sup
)]
411 public static String
sup(Object thisob
){
412 return "<SUP>"+Convert
.ToString(thisob
)+"</SUP>";
415 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_toLocaleLowerCase
)]
416 public static String
toLocaleLowerCase(Object thisob
){
417 return Convert
.ToString(thisob
).ToLower(CultureInfo
.CurrentUICulture
);
420 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_toLocaleUpperCase
)]
421 public static String
toLocaleUpperCase(Object thisob
){
422 return Convert
.ToString(thisob
).ToUpperInvariant();
425 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_toLowerCase
)]
426 public static String
toLowerCase(Object thisob
){
427 return Convert
.ToString(thisob
).ToLowerInvariant();
430 private static RegExpObject
ToRegExpObject(Object regExp
, VsaEngine engine
){
431 if (regExp
== null || regExp
is Missing
)
432 return (RegExpObject
)engine
.GetOriginalRegExpConstructor().Construct("", false, false, false);
433 RegExpObject result
= regExp
as RegExpObject
;
434 if (result
!= null) return result
;
435 Regex regex
= regExp
as Regex
;
436 if (regex
!= null) return new RegExpObject(regex
);
437 return (RegExpObject
)engine
.GetOriginalRegExpConstructor().Construct(Convert
.ToString(regExp
), false, false, false);
440 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_toString
)]
441 public static String
toString(Object thisob
){
442 StringObject strob
= thisob
as StringObject
;
443 if (strob
!= null) return strob
.value;
444 ConcatString concatStr
= thisob
as ConcatString
;
445 if (concatStr
!= null) return concatStr
.ToString();
446 IConvertible ic
= Convert
.GetIConvertible(thisob
);
447 if (Convert
.GetTypeCode(thisob
, ic
) == TypeCode
.String
) return ic
.ToString(null);
448 throw new JScriptException(JSError
.StringExpected
);
451 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_toUpperCase
)]
452 public static String
toUpperCase(Object thisob
){
453 return Convert
.ToString(thisob
).ToUpperInvariant();
456 [JSFunctionAttribute(JSFunctionAttributeEnum
.HasThisObject
, JSBuiltin
.String_valueOf
)]
457 public static Object
valueOf(Object thisob
){
458 return StringPrototype
.toString(thisob
);